package com.song.tools.mvc.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.song.tools.core.util.ObjectUtils;
import com.song.tools.mvc.mapper.BaseMapper;
import com.song.tools.mvc.request.PageRequest;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.*;

/**
 * 基础管理类
 *
 * @author song tools
 * @since 2024-06-19
 */
public abstract class BaseManager<Entity, EntityBo, Mapper extends BaseMapper<Entity>, Query extends BaseQuery, PrimaryKey extends Serializable, EntityConvertor extends com.song.tools.mvc.convertor.EntityConvertor<Entity, EntityBo>> {

    @Autowired
    protected Mapper mapper;

    @Autowired
    protected EntityConvertor entityConvertor;

    /**
     * BaseManager的范型类型
     */
    protected final Class<?>[] typeArguments = GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseManager.class);

    /**
     * Entity 的类型
     */
    protected Class<Entity> entityClass = this.currentModelClass();

    /**
     * EntityBo 的类型
     */
    protected Class<EntityBo> entityBoClass = this.currentModelBoClass();

    /**
     * Mapper 的类型
     */
    protected Class<Mapper> mapperClass = this.currentMapperClass();

    protected static final String ASC = "asc";
    protected static final String DESC = "desc";

    protected static final String DEFAULT_ORDER_BY_FIELD = "id";

    protected static final Integer DEFAULT_BATCH_SIZE = 100;

    public BaseManager() {
    }

    @SuppressWarnings("unchecked")
    protected Class<Entity> currentModelClass() {
        return (Class<Entity>) this.typeArguments[0];
    }

    @SuppressWarnings("unchecked")
    protected Class<EntityBo> currentModelBoClass() {
        return (Class<EntityBo>) this.typeArguments[1];
    }

    @SuppressWarnings("unchecked")
    protected Class<Mapper> currentMapperClass() {
        return (Class<Mapper>) this.typeArguments[2];
    }

    /**
     * 保存一条数据
     *
     * @param entityBo 实体bo
     */
    public int save(EntityBo entityBo) {
        if (ObjectUtils.isEmpty(entityBo)) {
            return 0;
        }
        Entity entity = entityConvertor.entityBoToEntity(entityBo);

        int rows = this.mapper.insert(entity);
        BeanUtil.copyProperties(entity, entityBo, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        return rows;
    }

    /**
     * 批量插入数据
     *
     * @param entityBoList 实体bo列表
     */
    public void saveBatch(List<EntityBo> entityBoList) {
        if (CollUtil.isNotEmpty(entityBoList)) {
            mapper.insertBatchSomeColumn(entityConvertor.entityBoToEntity(entityBoList), DEFAULT_BATCH_SIZE);
        }
    }

    /**
     * 通过ID修改一条数据
     *
     * @param entityBo 实体
     */
    public int updateByPrimaryKey(EntityBo entityBo) {
        return this.mapper.updateById(entityConvertor.entityBoToEntity(entityBo));
    }


    /**
     * 通过主键删除数据
     *
     * @param primaryKey 主键
     */
    public int deleteByPrimaryKey(PrimaryKey primaryKey) {
        return this.mapper.deleteById(primaryKey);
    }

    /**
     * 通过主键列表删除数据
     *
     * @param primaryKeys 主键列表
     */
    public int deleteBatchByPrimaryKeys(Collection<PrimaryKey> primaryKeys) {
        return this.mapper.deleteBatchIds(primaryKeys);
    }


    /**
     * 通过主键查询单条数据
     *
     * @param primaryKey 主键
     * @return 业务对象
     */
    public EntityBo getOneByPrimaryKey(PrimaryKey primaryKey, SFunction<Entity, ?> column) {
        return getOneByUniqueKey(primaryKey, column);
    }

    /**
     * 通过唯一键查询单条数据
     *
     * @param uniqueKey 唯一键
     * @return 业务对象
     */
    public EntityBo getOneByUniqueKey(Object uniqueKey, SFunction<Entity, ?> column) {
        LambdaQueryWrapper<Entity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(column, uniqueKey);
        return getOne(queryWrapper);
    }

    /**
     * 查询单条数据
     *
     * @param query 查询参数
     * @return 业务对象
     */
    public EntityBo getOne(Query query) {
        return getOne(this.encapsulateQueryWrapper(query));
    }

    /**
     * 通过查询条件查询单条数据
     *
     * @param queryWrapper 查询条件
     * @return 业务对象
     */
    public EntityBo getOne(LambdaQueryWrapper<Entity> queryWrapper) {
        // 查询单条数据
        Entity entity = this.mapper.selectOne(queryWrapper, true);

        // 根据查询结果转换业务对象
        return entityConvertor.entityToEntityBo(entity);
    }

    /**
     * 分页查询实现
     *
     * @param request 请求参数
     * @return 响应结果
     */
    public IPage<EntityBo> page(PageRequest<Query> request) {
        // 组装查询条件
        LambdaQueryWrapper<Entity> queryWrapper = encapsulateQueryWrapper(request.getData());

        // 分页查数据
        Page<Entity> entityPage = this.mapper.selectPage(new Page<>(request.getPageNum(), request.getPageSize()), queryWrapper);

        // 根据查询结果组装业务对象列表
        List<EntityBo> entityBos = createBo(entityPage.getRecords());

        // 返回业务分页结果
        return Page.<EntityBo>of(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal(), entityPage.searchCount()).setRecords(entityBos);
    }

    /**
     * 封装查询条件
     *
     * @param request 请求参数
     * @return 查询条件wrapper
     */
    public LambdaQueryWrapper<Entity> encapsulateQueryWrapper(Query request) {
        QueryWrapper<Entity> wrapper = new QueryWrapper<>();
        if (Objects.isNull(request)) {
            return wrapper.lambda();
        }

        // 处理查询字段
        String[] underLineFields = request.convertToUnderLineFields();
        if (Objects.nonNull(underLineFields) && underLineFields.length > 0) {
            wrapper.select(underLineFields);
        }

        // 处理排序规则
        String orderBy = request.getOrderBy();
        if (StrUtil.isNotBlank(orderBy)) {
            String[] orderByExpressions = orderBy.split(StrUtil.COMMA);
            List<String> ascFields = new ArrayList<>();
            List<String> descFields = new ArrayList<>();
            for (String orderByExpression : orderByExpressions) {
                if (orderByExpression.endsWith(ASC)) {
                    ascFields.add(orderByExpression.replace(StrUtil.DASHED + ASC, StrUtil.EMPTY));
                    continue;
                }
                if (orderByExpression.endsWith(DESC)) {
                    descFields.add(orderByExpression.replace(StrUtil.DASHED + DESC, StrUtil.EMPTY));
                }
            }

            // 没有排序规则，使用ID倒序排序
            if (CollUtil.isEmpty(descFields) && CollUtil.isEmpty(ascFields)) {
                wrapper.orderByDesc(DEFAULT_ORDER_BY_FIELD);
                return wrapper.lambda();
            }
            if (CollUtil.isNotEmpty(ascFields)) {
                wrapper.orderByAsc(ascFields);
            }
            if (CollUtil.isNotEmpty(descFields)) {
                wrapper.orderByDesc(descFields);
            }
        } else {
            // 没有排序规则，使用ID倒序排序
            wrapper.orderByDesc(DEFAULT_ORDER_BY_FIELD);
        }
        return wrapper.lambda();
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 查询条件
     * @return 实体Bo列表
     */
    public List<EntityBo> list(Wrapper<Entity> queryWrapper) {
        List<Entity> entities = this.mapper.selectList(queryWrapper);
        return entityConvertor.entityToEntityBo(entities);
    }

    /**
     * 查询列表
     *
     * @param query 查询条件
     * @return 实体Bo列表
     */
    public List<EntityBo> list(Query query) {
        List<Entity> entities = this.mapper.selectList(encapsulateQueryWrapper(query));
        return entityConvertor.entityToEntityBo(entities);
    }

    /**
     * 通过主键列表查询实体列表
     *
     * @param primaryKeys 主键列表
     * @return 实体Bo列表
     */
    public List<EntityBo> listByPrimaryKeys(List<PrimaryKey> primaryKeys) {
        if (CollUtil.isEmpty(primaryKeys)) {
            return Collections.emptyList();
        }
        List<Entity> entities = this.mapper.selectBatchIds(primaryKeys);
        return entityConvertor.entityToEntityBo(entities);
    }

    /**
     * 创建实体对应的BO对象
     *
     * @param entities 实体列表
     * @return BO对象列表
     */
    public List<EntityBo> createBo(List<Entity> entities) {
        if (CollUtil.isEmpty(entities)) {
            return Collections.emptyList();
        }
        return entityConvertor.entityToEntityBo(entities);
    }
}
